package wymiana.mbeans;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.primefaces.context.RequestContext;
import org.primefaces.event.FileUploadEvent;
import org.primefaces.model.DefaultStreamedContent;
import org.primefaces.model.StreamedContent;
import org.primefaces.model.UploadedFile;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import wymiana.forms.RegistrationForm;
import wymiana.domain.Authorities;
import wymiana.domain.Photo;
import wymiana.domain.User;
import wymiana.service.AuthenticationService;
import wymiana.service.AuthoritiesService;
import wymiana.service.PhotoService;
import wymiana.service.UserService;
import wymiana.utils.JSFUtils;

@ManagedBean(name = "userMBean")
// @RequestScoped
@SessionScoped
public class UserBean implements Serializable {

	/** serialization uid */
	private static final long serialVersionUID = 1406936377049046193L;
	private String login = null;

	private String password = null;

	private RegistrationForm registrationForm = null;

	private User loggedUser = null;
	private List<User> users;
	private List<User> filteredUsers;
	private User selectedUser;
	private static final Logger logger = Logger.getLogger(UserBean.class);

	@ManagedProperty("#{userService}")
	private UserService userService;

	@ManagedProperty("#{photoService}")
	private PhotoService photoService;

	@ManagedProperty("#{authService}")
	private AuthoritiesService authService;

	@ManagedProperty("#{authenticationService}")
	private AuthenticationService authenticationService;

	private Map<String, UploadedFile> uploadedFiles;

	private List<String> listImages;

	public String goToUsers() {
		return "listUsers";
	}

	public UserBean() {

	}

	public String doLogin() {
		ExternalContext context = FacesContext.getCurrentInstance()
				.getExternalContext();

		RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
				.getRequestDispatcher("/j_spring_security_check");

		try {
			dispatcher.forward((ServletRequest) context.getRequest(),
					(ServletResponse) context.getResponse());
		} catch (ServletException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		FacesContext.getCurrentInstance().responseComplete();
		RequestContext ctx = RequestContext.getCurrentInstance();
		try {
			String username = SecurityContextHolder.getContext()
					.getAuthentication().getName();
			this.loggedUser = this.userService.getUserByUsername(username);
			ctx.addCallbackParam("loggedIn", true);
			// return "startpage?faces-redirect=true";
		} catch (Exception e) {
			FacesMessage msg = null;
			msg = new FacesMessage(FacesMessage.SEVERITY_WARN,
					"Błąd logowania", "Niepoprawne dane logowania.");
			FacesContext.getCurrentInstance().addMessage("growl", msg);
			logger.debug("Niepoprawne logowanie");
			ctx.addCallbackParam("loggedIn", false);
		}

		return null;
	}

	public String register() {
		ExternalContext context = FacesContext.getCurrentInstance()
				.getExternalContext();

		User user = new User(this.registrationForm.getUsername(),
				this.registrationForm.getPass(), Boolean.valueOf(true),
				Boolean.valueOf(true), Boolean.valueOf(true),
				Boolean.valueOf(true), Boolean.valueOf(true),
				this.registrationForm.getName(),
				this.registrationForm.getSecondName(),
				this.registrationForm.getEmail(),
				this.registrationForm.getPhone(),
				this.registrationForm.getDateOfBirth());

		if ((this.registrationForm.getDateOfBirth() != null)
				&& ("".equals(this.registrationForm.getDateOfBirth())))
			;
		try {
			this.userService.create(user);
			Authorities role = new Authorities(user, "ROLE_USER");
			Collection roles = new ArrayList();
			roles.add(role);

			this.authService.create(role);

			UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
					user.getUsername(), user.getPassword());

			token.setDetails(new WebAuthenticationDetails(
					(HttpServletRequest) context.getRequest()));

			Authentication authentication = this.authenticationService
					.getAuthenticationManager().authenticate(token);

			SecurityContextHolder.getContext()
					.setAuthentication(authentication);

			this.loggedUser = user;
		} catch (DataIntegrityViolationException ex) {
			JSFUtils.addErrorMessage("Użytkownik o takim loginie juz istnieje.");
			logger.debug("Wystapil problem z rejestracja.", ex);
			return "";
		} catch (Exception e) {
			SecurityContextHolder.getContext().setAuthentication(null);
			logger.error("Wystapil problem z rejestracja.", e);
		}
		return "startpage";
	}

	public String madeAdmin() {
		// userService.addAdminRole(selectedUser);
		Authorities a = new Authorities(selectedUser, "ROLE_ADMIN");
		authService.create(a);

		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Użytkownikowi nadano prawa administratora");
		FacesContext.getCurrentInstance().addMessage(null, message);
		selectedUser = userService
				.getUserByUsername(selectedUser.getUsername());

		return "";
	}

	public String editUser() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String userId = (String) externalContext.getRequestParameterMap().get(
				"userId");

		this.selectedUser = this.userService.getUserByUsername(userId);

		return "editUser";
	}

	public String showUser() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String userId = (String) externalContext.getRequestParameterMap().get(
				"userId");

		this.selectedUser = this.userService.getUserByUsername(userId);

		return "showUser";
	}

	public StreamedContent getImage() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		if (FacesContext.getCurrentInstance().getRenderResponse()) {
			// So, we're rendering the view. Return a stub StreamedContent so
			// that it will generate right URL.
			return new DefaultStreamedContent();
		} else {
			String imageId = (String) externalContext.getRequestParameterMap()
					.get("imageIdD");
			Photo p = null;
			if (selectedUser.getPhotos() != null) {
				for (Photo photo : selectedUser.getPhotos()) {
					if (photo.getIdPhoto().toString().equals(imageId)) {
						p = photo;
					}
				}
			}
			StreamedContent image = null;
			if (p != null) {
				image = new DefaultStreamedContent(new ByteArrayInputStream(
						p.getPhoto()), "image/png");

				return image;
			}
		}

		return null;
	}

	public StreamedContent getLoggedImage() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		if (FacesContext.getCurrentInstance().getRenderResponse()) {
			// So, we're rendering the view. Return a stub StreamedContent so
			// that it will generate right URL.
			return new DefaultStreamedContent();
		} else {
			String imageId = (String) externalContext.getRequestParameterMap()
					.get("imageIdD");
			Photo p = null;
			if (loggedUser.getPhotos() != null) {
				for (Photo photo : loggedUser.getPhotos()) {
					if (photo.getIdPhoto().toString().equals(imageId)) {
						p = photo;
					}
				}
			}
			StreamedContent image = null;
			if (p != null) {
				image = new DefaultStreamedContent(new ByteArrayInputStream(
						p.getPhoto()), "image/png");

				return image;
			}
		}

		return null;
	}

	public String deleteActualPhoto() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String imageId = (String) externalContext.getRequestParameterMap().get(
				"imageIdD");

		photoService.deleteById(Integer.parseInt(imageId));
		int i = 0;
		for (Photo p : loggedUser.getPhotos()) {
			if (p.getIdPhoto().toString().equals(imageId)) {
				break;
			}
			i++;
		}
		loggedUser.getPhotos().remove(i);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Usunięto obraz");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "";
	}

	public String setAsMain() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String imageId = (String) externalContext.getRequestParameterMap().get(
				"imageIdD");
		for (Photo p : loggedUser.getPhotos()) {
			if (p.getMainPhoto()) {
				p.setMainPhoto(false);
				photoService.update(p);
			}

		}
		Photo p = photoService.getPhotoById(Integer.parseInt(imageId));
		p.setMainPhoto(true);
		photoService.update(p);
		loggedUser = userService.getUserByUsername(loggedUser.getUsername());
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Ustawiono jako głowne zdjęcie.");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "";
	}

	public void upload(FileUploadEvent event) {
		FacesMessage msg = new FacesMessage("Sukces! ", event.getFile()
				.getFileName() + " zostało dodane.");

		FacesContext.getCurrentInstance().addMessage(null, msg);
		UploadedFile file = event.getFile();
		String key = file.getFileName();
		if (this.uploadedFiles == null) {
			this.uploadedFiles = new HashMap<String, UploadedFile>();
		}
		this.uploadedFiles.put(key, file);
		if (this.listImages == null) {
			this.listImages = new ArrayList<String>();
		}
		this.listImages.add(key.toString());
	}

	public String deletePhoto() {
		ExternalContext externalContext = FacesContext.getCurrentInstance()
				.getExternalContext();

		String imageId = (String) externalContext.getRequestParameterMap().get(
				"imageId");
		uploadedFiles.remove(imageId);
		listImages.remove(imageId);

		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Usunięto obraz z listy");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "";

	}

	public String saveEditedPhotos() {

		List<Photo> photos = new ArrayList<Photo>();
		if (this.listImages != null) {
			for (String key : this.listImages) {
				Photo p = new Photo();
				UploadedFile f = (UploadedFile) this.uploadedFiles.get(key);
				p.setMainPhoto(Boolean.valueOf(false));
				p.setPhoto(f.getContents());
				photos.add(p);
				p.setUser(this.loggedUser);
			}
		}
		if (!photos.isEmpty()) {
			this.photoService.addPhotos(photos);
			if (loggedUser.getPhotos() == null) {
				loggedUser.setPhotos(photos);
			} else {
				loggedUser.getPhotos().addAll(photos);
			}
		}

		this.userService.update(loggedUser);
		listImages = new ArrayList();

		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "Zapisano zdjęcia");

		FacesContext.getCurrentInstance().addMessage(null, message);

		return "";
	}

	public StreamedContent getMainPhoto() {
		Photo p = null;
		if (selectedUser.getPhotos() != null) {
			for (Photo photo : selectedUser.getPhotos()) {
				if (photo.getMainPhoto()) {
					p = photo;
				}
			}
		}

		StreamedContent image = null;
		if (p != null) {
			image = new DefaultStreamedContent(new ByteArrayInputStream(
					p.getPhoto()), "image/png");

			return image;
		}
		return null;
	}

	public String doGallery() {
		return "editPhotos";
	}

	public String saveEditedUser() {
		this.userService.update(this.selectedUser);
		return "listUsers";
	}

	public String addUser() {
		User user = new User(this.registrationForm.getUsername(),
				this.registrationForm.getPass(), Boolean.valueOf(true),
				Boolean.valueOf(true), Boolean.valueOf(true),
				Boolean.valueOf(true), Boolean.valueOf(true),
				this.registrationForm.getName(),
				this.registrationForm.getSecondName(),
				this.registrationForm.getEmail(),
				this.registrationForm.getPhone(),
				this.registrationForm.getDateOfBirth());

		this.userService.create(user);
		Authorities role = new Authorities(user, "ROLE_USER");
		Collection roles = new ArrayList();
		roles.add(role);

		this.authService.create(role);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "dodano uzytkownika");
		FacesContext.getCurrentInstance().addMessage(null, message);
		return null;
	}

	public String doListUsers() {
		return "listUsers";
	}

	public String listUsers() {
		return null;
	}

	public String doChangeSettings() {
		return "changeSettings";
	}

	public String changeSettings() {
		this.userService.update(this.loggedUser);
		FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
				"Sukces: ", "zmieniono ustawienia");
		FacesContext.getCurrentInstance().addMessage(null, message);

		return null;
	}

	public String doChangePassword() {
		return "changePassword";
	}

	public String changePassword() {
		if (!this.loggedUser.getPassword().equals(
				this.registrationForm.getPassOld())) {
			FacesMessage message = new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "blad: ",
					"Stare hasło niepoprawne");
			FacesContext.getCurrentInstance().addMessage(null, message);
		} else {
			this.loggedUser.setPassword(this.registrationForm.getPass());
			this.userService.update(this.loggedUser);
			FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
					"Sukces: ", "Poprawnie zmieniono haslo");
			FacesContext.getCurrentInstance().addMessage(null, message);
		}

		return null;
	}

	public String home() {
		logger.info(new String("dsadsad"));
		return "startpage";
	}

	public String doRegister() {
		return "register";
	}

	public String doAddUser() {
		return "addUser";
	}

	public String getLogin() {
		return this.login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getPassword() {
		return this.password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public RegistrationForm getRegistrationForm() {
		if (this.registrationForm == null) {
			this.registrationForm = new RegistrationForm();
		}
		return this.registrationForm;
	}

	public void setRegistrationForm(RegistrationForm registrationForm) {
		this.registrationForm = registrationForm;
	}

	public UserService getUserService() {
		return this.userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public AuthoritiesService getAuthService() {
		return this.authService;
	}

	public void setAuthService(AuthoritiesService authService) {
		this.authService = authService;
	}

	public AuthenticationService getAuthenticationService() {
		return this.authenticationService;
	}

	public void setAuthenticationService(
			AuthenticationService authenticationService) {
		this.authenticationService = authenticationService;
	}

	private Object getSpringBean(String name) {
		WebApplicationContext ctx = WebApplicationContextUtils
				.getRequiredWebApplicationContext((ServletContext) FacesContext
						.getCurrentInstance().getExternalContext().getContext());

		return ctx.getBean(name);
	}

	public User getLoggedUser() {
		try {
			String username = SecurityContextHolder.getContext()
					.getAuthentication().getName();
			this.loggedUser = this.userService.getUserByUsername(username);
			// return "startpage?faces-redirect=true";
		} catch (Exception e) {
		}
		return this.loggedUser;
	}

	public void setLoggedUser(User loggedUser) {
		this.loggedUser = loggedUser;
	}

	public List<User> getUsers() {
		this.users = this.userService.getAllUsers();
		return this.users;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

	public User getSelectedUser() {
		return this.selectedUser;
	}

	public void setSelectedUser(User selectedUser) {
		this.selectedUser = selectedUser;
	}

	/**
	 * @return the filteredUsers
	 */
	public List<User> getFilteredUsers() {
		return filteredUsers;
	}

	/**
	 * @param filteredUsers
	 *            the filteredUsers to set
	 */
	public void setFilteredUsers(List<User> filteredUsers) {
		this.filteredUsers = filteredUsers;
	}

	/**
	 * @return the photoService
	 */
	public PhotoService getPhotoService() {
		return photoService;
	}

	/**
	 * @param photoService
	 *            the photoService to set
	 */
	public void setPhotoService(PhotoService photoService) {
		this.photoService = photoService;
	}

	/**
	 * @return the uploadedFiles
	 */
	public Map<String, UploadedFile> getUploadedFiles() {
		return uploadedFiles;
	}

	/**
	 * @param uploadedFiles
	 *            the uploadedFiles to set
	 */
	public void setUploadedFiles(Map<String, UploadedFile> uploadedFiles) {
		this.uploadedFiles = uploadedFiles;
	}

	/**
	 * @return the listImages
	 */
	public List<String> getListImages() {
		return listImages;
	}

	/**
	 * @param listImages
	 *            the listImages to set
	 */
	public void setListImages(List<String> listImages) {
		this.listImages = listImages;
	}
}
